package com.study.talk.ui.app.base

import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannelGroup
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.ContentValues
import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia.ImageOnly
import androidx.activity.viewModels
import androidx.annotation.AnyThread
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.study.common.DateUtil
import com.study.common.EventBusUtil
import com.study.common.GSONUtil
import com.study.common.MDParser
import com.study.common.ToastUtil
import com.study.common.annotation.Desc
import com.study.common.event.Constants
import com.study.common.event.OtherMessage
import com.study.talk.App
import com.study.talk.R
import com.study.talk.ai.AiModel
import com.study.talk.data.model.GroupMessageRecord
import com.study.talk.data.model.MessageRecord
import com.study.talk.di.AppModule
import com.study.talk.netty.NettyClient
import com.study.talk.netty.message.MessageType
import com.study.talk.netty.message.TalkMessage
import com.study.talk.netty.message.request.AcceptGroupRequest
import com.study.talk.netty.message.request.AcceptJoinGroupRequest
import com.study.talk.netty.message.request.AcceptRequest
import com.study.talk.netty.message.response.AcceptGroupResponse
import com.study.talk.netty.message.response.AcceptJoinGroupResponse
import com.study.talk.netty.message.response.AcceptResponse
import com.study.talk.netty.message.response.AddUserResponse
import com.study.talk.netty.message.response.ApplyGroupResponse
import com.study.talk.netty.message.response.GroupMessageResponse
import com.study.talk.netty.message.response.GroupMessageSelfResponse
import com.study.talk.netty.message.response.InviteGroupResponse
import com.study.talk.netty.message.response.MessageResponse
import com.study.talk.netty.message.response.MessageSelfResponse
import com.study.talk.ui.app.chat.ChatActivity
import com.study.talk.ui.app.chat.GroupChatActivity
import com.study.talk.ui.app.friend.UserDetailsActivity
import com.study.talk.ui.app.group.InviteFriendActivity
import com.study.talk.ui.app.group.info.GroupInfoActivity
import com.study.talk.ui.app.moment.MomentsActivity
import com.study.talk.utils.ActivityUtil
import com.study.talk.utils.PopWindowUtil
import com.study.talk.utils.alert.AlertUtil
import com.study.talk.utils.alert.CustomDialog
import com.study.talk.utils.extras.showToast
import com.study.talk.utils.extras.start
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode


@AndroidEntryPoint
open class BaseActivity : AppCompatActivity() {

    companion object {
        private const val TAG = "BaseActivity"
    }

    var uri: Uri? = null

    private val vm by viewModels<BaseViewModel>()

    private val notifyManager: NotificationManager by lazy {
        getSystemService(NOTIFICATION_SERVICE) as NotificationManager
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onMessageEvent(message: OtherMessage) {
        if (this.javaClass.name == ActivityUtil.topName(this)) {
            when (message.event) {
                Constants.EVENT_NETTY_DISCONNECT -> {
                    showToast("服务器断开连接")
                }

                Constants.EVENT_NETTY_RECONNECT -> {
                    run {
                        showToast("服务器重新连接成功")
                    }
                    run {
                        showToast("请先登录！")
                    }
                }

                Constants.NEED_LOGIN -> {
                    showToast("请先登录！")
                }
            }
        }
    }

    @Desc("EventBus消息分发")
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onMessageEvent(message: TalkMessage) {
        Log.d(TAG, "onMessageEvent: ${GSONUtil.toJson(message)}")
        if (this.javaClass.name == ActivityUtil.topName(this)) {
            when (message.type) {
                MessageType.ADD_USER_RESPONSE -> handleAddUserResponse(message as AddUserResponse)
                MessageType.ACCEPT_RESPONSE -> handleAcceptAddUserResponse(message as AcceptResponse)
                MessageType.ACCEPT_GROUP_RESPONSE -> handleAcceptGroupResponse(message as AcceptGroupResponse)
                MessageType.INVITE_GROUP_RESPONSE -> handleInviteGroupResponse(message as InviteGroupResponse)
                MessageType.APPLY_GROUP_RESPONSE -> handleApplyGroupResponse(message as ApplyGroupResponse)
                MessageType.ACCEPT_JOIN_GROUP_RESPONSE -> handleAcceptJoinGroupResponse(message as AcceptJoinGroupResponse)
                MessageType.SEND_MESSAGE_RESPONSE -> handleMessageResponse(message as MessageResponse)
                MessageType.GROUP_MESSAGE_RESPONSE -> handleGroupMessageResponse(message as GroupMessageResponse)
                MessageType.MESSAGE_SELF_RESPONSE -> handleMessageSelfResponse(message as MessageSelfResponse)
                MessageType.GROUP_MESSAGE_SELF_RESPONSE -> handleGroupMessageSelfResponse(message as GroupMessageSelfResponse)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        EventBusUtil.registerEvent(this)
        super.onCreate(savedInstanceState)
    }

    override fun onDestroy() {
        EventBusUtil.unregisterEvent(this)
        super.onDestroy()
    }

    @Desc("发送消息后的响应预处理")
    private fun handleMessageSelfResponse(response: MessageSelfResponse) {
        if (response.success) {
            vm.addMsg(response)
        } else {
            showToast(response.reason)
        }
    }

    @Desc("发送群消息后的响应预处理")
    private fun handleGroupMessageSelfResponse(response: GroupMessageSelfResponse) {
        if (response.success) {
            vm.addGroupMsg(response)
        } else {
            showToast(response.reason)
        }
    }

    @Desc("消息未读保存")
    private fun handleMessageResponse(messageResponse: MessageResponse) {
        val msg = MessageRecord(
            messageResponse, false, false
        )
        if (ActivityUtil.topName(this) == "com.study.talk.app.chat.ChatActivity") {
            msg.read = true
            vm.addMsg(msg)
        } else {
            vm.addMsg(msg)
            val intent = Intent(this@BaseActivity, ChatActivity::class.java)
            intent.putExtra(ChatActivity.DATA_NAME, msg.userId)
            if (app.hide) {
                //发送通知 id是通知的id，覆盖的话下次还需要使用相同的id发送通知，之前的通知就会覆盖
                notifyManager.notify(msg.userId, launcherNotification(msg, intent))
            } else {
                PopWindowUtil.showPopWindow(
                    context = this@BaseActivity, view = window.decorView, message = msg
                ) { startActivity(intent) }
            }
        }
    }

    @Desc("群聊消息未读保存")
    private fun handleGroupMessageResponse(messageResponse: GroupMessageResponse) {
        val msg = GroupMessageRecord(
            messageResponse, false, false
        )
        if (ActivityUtil.topName(this) == "com.study.talk.app.chat.GroupChatActivity") {
            msg.read = true
            vm.addGroupMsg(msg)
        } else {
            vm.addGroupMsg(msg)
            val intent = Intent(this@BaseActivity, GroupChatActivity::class.java)
            intent.putExtra(GroupChatActivity.DATA_NAME, msg.groupId)
            if (app.hide) {
                notifyManager.notify(msg.groupId, launcherGroupNotification(msg, intent))
            } else {
                PopWindowUtil.showPopWindow(
                    this@BaseActivity, window.decorView, msg
                ) { startActivity(intent) }
            }
        }
    }


    @Desc("好友申请处理")
    private fun handleAddUserResponse(response: AddUserResponse) {
        AlertUtil.showCustomDialog(
            this@BaseActivity, "好友申请", "用户${response.inviteName}申请成为你的好友"
        ) { accept ->
            val acceptRequest = AcceptRequest(response.inviteId, accept, DateUtil.currentTime())
            NettyClient.sendMessage(acceptRequest)
            if (accept) {
                lifecycleScope.launch(Dispatchers.Main) {
                    delay(2000)
                    updateFriendList()
                }
            }
        }
    }

    @Desc("好友申请结果通知")
    private fun handleAcceptAddUserResponse(acceptResponse: AcceptResponse) {
        AlertUtil.show(
            this@BaseActivity,
            "好友添加${if (acceptResponse.success) "同意" else "拒绝"}提醒",
            "用户${acceptResponse.invitedName}${if (acceptResponse.success) "同意" else "拒绝"}了你的好友申请"
        )
        if (acceptResponse.success) {
            updateFriendList()
        }
    }


    @Desc("加入群聊通知")
    private fun handleAcceptGroupResponse(acceptGroupResponse: AcceptGroupResponse) {
        if (acceptGroupResponse.success) {
            AlertUtil.show(
                this@BaseActivity,
                "${acceptGroupResponse.groupName}群消息提醒",
                "用户${acceptGroupResponse.acceptUserName}加入了群聊"
            )
        } else {
            AlertUtil.show(
                this@BaseActivity,
                "拒绝加入群聊提醒",
                "用户${acceptGroupResponse.acceptUserName}拒绝加入群聊"
            )
        }
    }

    @Desc("同意入群通知")
    private fun handleAcceptJoinGroupResponse(acceptJoinGroupResponse: AcceptJoinGroupResponse) {
        if (acceptJoinGroupResponse.success) {
            AlertUtil.show(
                this@BaseActivity,
                "群消息提醒",
                "你已成功加入群聊" + acceptJoinGroupResponse.groupName
            )
            updateGroupList()
        } else {
            AlertUtil.show(
                this@BaseActivity,
                "加入群聊" + acceptJoinGroupResponse.groupName + "失败",
                "申请没有通过"
            )
        }
    }

    @Desc("邀请加入群聊处理")
    private fun handleInviteGroupResponse(response: InviteGroupResponse) {
        AlertUtil.showCustomDialog(
            this@BaseActivity,
            "邀请加入群聊提醒",
            "用户${response.inviteUserName}邀请你加入群聊${response.groupName}"
        ) { accept ->
            NettyClient.sendMessage(
                AcceptGroupRequest(
                    response.groupId,
                    app.localUserId,
                    response.inviteUserId,
                    accept,
                    DateUtil.currentTime()
                )
            )
        }
    }

    @Desc("有人申请加入群聊消息处理")
    private fun handleApplyGroupResponse(response: ApplyGroupResponse) {
        AlertUtil.showCustomDialog(
            this@BaseActivity,
            "申请加入群聊提醒",
            "用户${response.applyUserName}申请加入群聊${response.groupName}"
        ) { accept ->
            NettyClient.sendMessage(
                AcceptJoinGroupRequest(
                    response.groupId, response.applyUserId, accept, DateUtil.currentTime()
                )
            )
        }
    }


    val app: App
        get() = application as App

    fun checkInput(textView: EditText, toast: String): Boolean {
        if (TextUtils.isEmpty(editTrim(textView))) {
            ToastUtil.showToast(this, toast)
            return true
        }
        return false
    }

    fun setText(editText: EditText, text: String?) {
        editText.setText(text)
    }


    @Desc("显示底部选择图像弹窗，由用户选择拍照或选择图像")
    fun showSelectPhotoDialog(
        selectPhotoLauncher: ActivityResultLauncher<PickVisualMediaRequest>,
        takePhotoLauncher: ActivityResultLauncher<Uri>
    ) {
        val dialog = BottomSheetDialog(this@BaseActivity)

        val bottomDialogView =
            LayoutInflater.from(this@BaseActivity).inflate(R.layout.dialog_bottom, null)
        val takePhoto = bottomDialogView.findViewById<TextView>(R.id.take_photo)
        val selectPhoto = bottomDialogView.findViewById<TextView>(R.id.select_photo)
        val cancel = bottomDialogView.findViewById<TextView>(R.id.cancel)

        //点击拍照
        takePhoto.setOnClickListener { _ ->
            takePhoto(takePhotoLauncher)
            dialog.dismiss()
        }

        //点击相册
        selectPhoto.setOnClickListener { _ ->
            selectPhoto(selectPhotoLauncher)
            dialog.dismiss()
        }

        //点击取消 弹窗消失
        cancel.setOnClickListener { _ -> dialog.dismiss() }

        dialog.setContentView(bottomDialogView)
        dialog.show()
    }

    @Desc("更新好友列表")
    @AnyThread
    fun updateFriendList() {
        lifecycleScope.launch {
            app.updateFriends(vm.getFriends())
        }
    }


    @Desc("更新群聊列表")
    @AnyThread
    fun updateGroupList() {
        lifecycleScope.launch {
            app.updateGroups(vm.getGroups())
        }
    }

    @Desc("输入框去空格")
    private fun editTrim(text: EditText): String {
        return text.text.toString().trim { it <= ' ' }
    }


    @Desc("选择图片")
    private fun selectPhoto(selectPhotoLauncher: ActivityResultLauncher<PickVisualMediaRequest>) {
        selectPhotoLauncher.launch(
            PickVisualMediaRequest.Builder().setMediaType(ImageOnly).build()
        )
    }

    @Desc("拍照并换返回")
    private fun takePhoto(takePhotoLauncher: ActivityResultLauncher<Uri>) {
        val contentValues = ContentValues()
        contentValues.put(
            MediaStore.MediaColumns.DISPLAY_NAME, "IMG_${System.currentTimeMillis()}.jpg"
        )
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
        uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
        uri?.let { takePhotoLauncher.launch(it) }
    }

    @Desc("创建通知组")
    private fun createNotificationGroup(groupId: String, groupName: String) {
        val group = NotificationChannelGroup(groupId, groupName)
        val notificationManager = getSystemService(
            NOTIFICATION_SERVICE
        ) as NotificationManager
        notificationManager.createNotificationChannelGroup(group)
    }

    @Desc("加载用户头像")
    fun loadUserAvatar(imageView: ImageView) {
        Glide.with(this@BaseActivity).load(AppModule.getWebUrl() + app.userInfo.avatar)
            .into(imageView)
    }


    @Desc("手动显示键盘")
    fun showKeyboard(view: View) {
        val imm = view.context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
        view.requestFocus()
        imm.showSoftInput(view, 0)
    }

    @Desc("手动隐藏键盘")
    fun hideKeyboard(view: View) {
        val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(view.windowToken, 0)
    }

    private fun launcherNotification(msg: MessageRecord, intent: Intent): Notification {
        return NotificationCompat.Builder(this@BaseActivity, "畅聊好友消息") //新建通知
            .setContentTitle("来自好友${msg.nickname}的消息") //通知标题
            .setContentText(if (msg.messageType == 1) "[图片]" else msg.content) //通知内容
            .setAutoCancel(true) //点击通知后通知消失
            .setWhen(System.currentTimeMillis()) //什么时候发送通知
            .setSmallIcon(R.drawable.notification) //通知的图标
            .setLargeIcon(
                BitmapFactory.decodeResource(resources, R.mipmap.app_logo)
            ).setContentIntent(
                PendingIntent.getActivity( //设置通知意图 ,放入点击通知后需要操作
                    this@BaseActivity, 0, intent, PendingIntent.FLAG_IMMUTABLE
                )
            ).build()
    }

    private fun launcherGroupNotification(msg: GroupMessageRecord, intent: Intent): Notification {
        return NotificationCompat.Builder(this@BaseActivity, "畅聊群聊消息")
            .setContentTitle("来自群聊成员${msg.nickname}的消息")
            .setContentText(if (msg.messageType == 1) "[图片]" else msg.content).setAutoCancel(true)
            .setWhen(System.currentTimeMillis()).setSmallIcon(R.drawable.notification).setLargeIcon(
                BitmapFactory.decodeResource(
                    resources, R.mipmap.app_logo
                )
            ).setContentIntent(
                PendingIntent.getActivity(
                    this@BaseActivity, 0, intent, PendingIntent.FLAG_IMMUTABLE
                )
            ).build()
    }

    fun buildUserMsg(content: String): ChatMessage {
        return ChatMessage.builder().role(ChatMessageRole.USER).content(content).build()
    }

    fun buildSystemMsg(content: String): ChatMessage {
        return ChatMessage.builder().role(ChatMessageRole.SYSTEM).content(content).build()
    }

    /** 智能分析文本内容 */
    fun analyzeChatContent(content: String) {
        val dialog = CustomDialog(this)
        val contentView = dialog.createView(this, R.layout.smart_analyze_alert)
        val title = contentView.findViewById<TextView>(R.id.alert_title)
        val message = contentView.findViewById<TextView>(R.id.alert_message)
        val question = buildString {
            append("在聊天过程中,好友说:").append(content).append("\n").append("帮忙分析一下")
        }
        val disposable = AiModel.sendMsg(listOf(buildUserMsg(question)), start = {
            lifecycleScope.launch(Dispatchers.Main) {
                title.text = "分析中..."
            }
        }, subscribe = {
            message.text = MDParser.toSpanned(it)
        }, finish = {
            lifecycleScope.launch(Dispatchers.Main) {
                title.text = "分析完成"
            }
        }, error = {
            showToast("访问出错!")
        })
        contentView.apply {
            findViewById<TextView>(R.id.alert_ok).setOnClickListener {
                disposable.dispose()
                dialog.dismiss()
            }
            findViewById<TextView>(R.id.alert_cancel).setOnClickListener {
                disposable.dispose()
                dialog.dismiss()
            }
        }
        dialog.show()
    }
}
